package com.lovi.thread_;



import com.lovi.common.MessageType;
import com.lovi.common.Message;
import com.lovi.common.OfflineMessageMap;
import com.lovi.common.UsersMap;
import com.lovi.utils.StreamUtils;
import lombok.Data;


import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 * 开启服务端与客户端连接通信的线程
 */
@Data
public class ServerConnectClientThread extends Thread{
    //线程同步，持有socket对象
    private Socket socket;
    //服务器与具体用户进行连接
    private String userId;
    public ServerConnectClientThread(Socket socket,String userId){
        this.socket = socket;
        this.userId = userId;
    }
    @Override
    public void run() {
        System.out.println("服务器与用户"+userId+"已建立信息通道");
        //服务端需要不断的读取客户端的信息
        while (true){
            try {
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Message msg =(Message)ois.readObject();
                //普通聊天消息
                if(MessageType.MESSAGE_COMM_MES.equals(msg.getMestype())){
                    //离线用户
                    if(UsersMap.isOfflineUser(msg.getGetter())){
                        //存储离线消息
                        OfflineMessageMap.addOffLineMessage(msg.getGetter(),msg);
                        continue;
                    }
                    //在线用户，拿到接受者消息的线程，把msg发送过去
                    ServerConnectClientThread thread = ManageServerConnectClientThread
                            .getServerConnectClientThread(msg.getGetter());
                    if(thread==null) continue;
                    ObjectOutputStream oos = new ObjectOutputStream(thread.getSocket().getOutputStream());
                    if (oos!=null)  oos.writeObject(msg);
                }
                //获取在线用户列表
                if(MessageType.MESSAGE_GET_ONLINE_FRIEND.equals(msg.getMestype())){
                    System.out.println("用户"+msg.getSender()+"请求在线用户列表");
                    //要求拿到在线用户列表
                    Message msg2 = new Message();
                    msg2.setGetter(msg.getSender());
                    msg2.setMestype(MessageType.MESSAGE_RET_ONLINE_FRIEND);
                    msg2.setContent(ManageServerConnectClientThread.getOnlineUsers());
                    ServerConnectClientThread thread = ManageServerConnectClientThread.getServerConnectClientThread(msg.getSender());
                    if(thread == null) continue;
                    //发送过去
                    ObjectOutputStream oos = new ObjectOutputStream(thread.getSocket().getOutputStream());
                    oos.writeObject(msg2);
                }
                //群发消息
                if(MessageType.MESSAGE_TO_ALL_MES.equals(msg.getMestype())){
                    //离线用户
                    List<String> offlineUsers = UsersMap.getOfflineUsers();
                    if(offlineUsers!=null && offlineUsers.size()>0){
                        for (String userId : offlineUsers) {
                            //存储离线消息
                            OfflineMessageMap.addOffLineMessage(userId,msg);
                        }
                    }
                    //在线用户
                    //给出了本人之外的人的消息的线程，发送msg
                    String onlineUsers = ManageServerConnectClientThread.getOnlineUsers();
                    String[] users = onlineUsers.split(" ");
                    for (String userId : users) {
                        if(userId.equals(msg.getSender())){
                            continue;
                        }
                        ServerConnectClientThread thread = ManageServerConnectClientThread
                                .getServerConnectClientThread(userId);
                        if (thread == null) continue;
                        ObjectOutputStream oos = new ObjectOutputStream(thread.getSocket().getOutputStream());
                        oos.writeObject(msg);
                    }
                }
                //退出系统
                if(MessageType.MESSAGE_CLIENT_EXIT.equals(msg.getMestype())){
                    System.out.println("用户"+msg.getSender()+"请求退出系统");
                    Message msg3 = new Message();
                    msg3.setGetter(msg.getSender());
                    msg3.setMestype(MessageType.MESSAGE_CLIENT_EXIT);
                    msg3.setContent("服务器已断开连接");
                    ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                    oos.writeObject(msg3);
                    //从线程集合中移除
                    ManageServerConnectClientThread.removeServerConnectClientThread(userId);
                    //关闭socket
                    socket.close();
                    //退出线程
                    break;
                }
                //获取文件信息
                if(MessageType.MESSAGE_FILE_MES.equals(msg.getMestype())){
                    //先测试是否可以下载文件
                    System.out.println("=========服务器文件下载页=========");
                    //离线用户
                    if(UsersMap.isOfflineUser(msg.getGetter())){
                        //存储离线消息
                        OfflineMessageMap.addOffLineMessage(msg.getGetter(),msg);
                        continue;
                    }
                    ServerConnectClientThread thread = ManageServerConnectClientThread
                            .getServerConnectClientThread(msg.getGetter());
                    if (thread == null) continue;
                    //直接转发
                    new ObjectOutputStream(thread.getSocket().getOutputStream()).writeObject(msg);
                }
                //离线消息
                if(MessageType.MESSAGE_OFFLINE_MES.equals(msg.getMestype())){
                    ServerConnectClientThread thread = ManageServerConnectClientThread.getServerConnectClientThread(msg.getSender());
                    if (thread == null) continue;
                    //拿到用户对应的离线消息集合
                    ArrayList<Message> offLineMessageList = OfflineMessageMap.getOffLineMessage(msg.getSender());
                    if(offLineMessageList!=null && offLineMessageList.size() > 0){
                        for (Message message : offLineMessageList) {
                            // 这里一定要new ObjectOutputStream，因为我们的客户端读取消息是每个message
                            // 都会new一个新的ObjectInputStream来读取
                            // 而ObjectOutputStream实例在序列化，new实例的时候会添加一个head对象，
                            // 而同一个实例则不会反复添加head，所以之后就直接没有head直接就writer了
                            // 而在ObjectInputStream实例在第一次new的时候，会去掉head，之后就会直接读取
                            // 报错 invalid type code: AC 就在于，我们客户端的反序列化是是while循环读取
                            // 每次都会new ObjectInputStream 也就是执行反序列化操作，会去掉head
                            // 但是我们同一个ObjectOutputStream实例第二次之后就会没有head！所以！就会报错！
                            // 这就是为什么debug的时候第一步
                            // ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                            // 就直接报错了！！
                            ObjectOutputStream oos = new ObjectOutputStream(thread.getSocket().getOutputStream());
                            oos.writeObject(message);
                        }
                        //从离线集合中移除该用户的所有离线消息
                        OfflineMessageMap.removeOffLineMessage(msg.getSender());
                    }

                }
            } catch (IOException | ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }

    }
}
